﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using ServBus.ListForm2010.Utility;
using ServBus.ListForm2010.Resources;
using System.Collections;

namespace ServBus.ListForm2010.Layouts.InfoBus2010
{
    public partial class LookupFormGenerator : LayoutsPageBase
    {
        #region Global Variable

        private SPList mList;
        private SPList sList;
        private SPWeb mWeb;
        private SPSite mSite;
        private InfoPathContext context;
        private string cTypeResrouceFolder;
        private string contentTypeName;
        private List<string> sContentTypes;
        private static DllResource Resource = new DllResource("ServBus.ListForm2010.Common.Resources|AppPages");

        #endregion

        #region Control Event

        protected void downloadFileClick(Exception ex)
        {
            LTException.Text = ex.ToString();
            errorPanel.Visible = true;
            ErrorLog.Write("ListFormInner" + "\r\n" + Request.Url + "\r\n" + ex.Message + "\r\n" + ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                if (!Page.IsPostBack)
                {
                    InitialPage();
                }
            }
            catch (Exception ex)
            {
                downloadFileClick(ex);
            }
        }

        protected void createlkpFormButtonClick(object sender, EventArgs e)
        {
            try
            {
                string xsnLocation = "";
                string destFolderUrl = "";
                string _siteUrl = SPContext.Current.Site.Url;
                Guid _siteId = SPContext.Current.Site.ID;

                Guid _webId = SPContext.Current.Web.ID;
                Guid _listId = new Guid(Request["source"]);

                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite _site = new SPSite(_siteId))
                    {
                        using (SPWeb _web = Site.OpenWeb(_webId))
                        {
                            _web.AllowUnsafeUpdates = true;

                            mList = _web.Lists[_listId];
                            string mContentTypeName = Convert.ToString(Request["cType"]);
                            SPContentType mContentType = mList.ContentTypes[mContentTypeName];
                            contentTypeName = mContentType.Name;



                            SPList _list = _web.Lists[_listId];
                            SPContentType _cType = _list.ContentTypes[contentTypeName];
                            xsnLocation = _web.Url + "/" + _cType.ResourceFolder.Url + "/template.xsn";

                            bool configItemUpdated = updateConfigList(_web, Convert.ToString(mList.ID), Convert.ToString(mContentType.Id));

                            if (!_web.GetFile(xsnLocation).Exists)
                            {

                                //display_lb.aspx, edit_lb.aspx, new_lb.aspx
                                destFolderUrl = _cType.ResourceFolder.ServerRelativeUrl;
                                string listParameter = "listId=" + _list.ID.ToString();
                                string cTypeParameter = "ctypeId=" + _cType.Id.ToString();
                                string uploadFileName = Microsoft.SharePoint.Utilities.SPUtility.GetGenericSetupPath(@"TEMPLATE\LAYOUTS\InfoBus2010\Template.aspx");
                                FileStream fileStream = File.Open(uploadFileName, FileMode.Open);
                                _web.Files.Add(destFolderUrl + "/display_lb.aspx", fileStream, true);
                                _cType.DisplayFormUrl = destFolderUrl + "/display_lb.aspx?" + listParameter + "%26" + cTypeParameter;
                                _web.Files.Add(destFolderUrl + "/edit_lb.aspx", fileStream, true);
                                _cType.EditFormUrl = destFolderUrl + "/edit_lb.aspx?" + listParameter + "%26" + cTypeParameter;
                                _web.Files.Add(destFolderUrl + "/new_lb.aspx", fileStream, true);
                                _cType.NewFormUrl = destFolderUrl + "/new_lb.aspx?" + listParameter + "%26" + cTypeParameter;

                                //RegisterEventReceiver(_list);

                                fileStream.Close();
                                _cType.Update();
                                _list.Update();

                                InitialContextVar(_siteUrl, _webId, _listId);
                                cTypeResrouceFolder = _cType.ResourceFolder.Name;
                                context.ListContentTypeName = _cType.Name;
                                GenerateXSN();

                            }
                            else
                            {
                                if (configItemUpdated)
                                {
                                    InitialContextVar(_siteUrl, _webId, _listId);
                                    cTypeResrouceFolder = _cType.ResourceFolder.Name;
                                    context.ListContentTypeName = _cType.Name;
                                    GenerateXSN();
                                }
                            }
                        }
                    }
                });

                Response.Write("<script type='text/javascript'>var spOpener = new ActiveXObject('SharePoint.OpenXMLDocuments');if (spOpener != null) {var x = spOpener.CustomizeTemplate('" + xsnLocation + "'); }window.frameElement.commitPopup('ok');</script>");

            }
            catch (Exception ex)
            {
                downloadFileClick(ex);
            }
        }

        protected void cancelButtonClick(object sender, EventArgs e)
        {
            Response.Write("<script type='text/javascript'>window.frameElement.commitPopup('cancel');</script>");
        }

        #endregion

        #region Private Method

        private bool InitialPage()
        {
            //Initial Parameters
            bool initialStatus = false;
            if (!string.IsNullOrEmpty(Request["source"]))
            {
                initialStatus = true;
                Guid _siteId = SPContext.Current.Site.ID;
                Guid _webId = SPContext.Current.Web.ID;
                Guid _listId = new Guid(Request["source"]);
                string cTypeName = Request["cType"];
                //Set lkpFormbl default status
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite _site = new SPSite(_siteId))
                    {
                        using (SPWeb _web = _site.OpenWeb(_webId))
                        {
                            mList = _web.Lists[_listId];
                            //TreeNode rootNode = new TreeNode(_web.Title);
                            SPContentType mContentType = mList.ContentTypes[cTypeName];
                            ArrayList sListConfigValue = getConfigItem(_web, Convert.ToString(mList.ID), Convert.ToString(mContentType.Id));
                            foreach (SPList sList in _web.Lists)
                            {
                                TreeNode listNode = new TreeNode(sList.Title);

                                bool isChildList = false;
                                foreach (SPContentType sContentType in sList.ContentTypes)
                                {
                                    foreach (SPField field in sContentType.Fields)
                                    {
                                        if (field is SPFieldLookup)
                                        {
                                            SPFieldLookup lkpFld = field as SPFieldLookup;
                                            if (!string.IsNullOrEmpty(lkpFld.LookupList)
                                                && lkpFld.LookupList.ToLower().Contains(mList.ID.ToString().ToLower()))
                                            {
                                                TreeNode cTypeNode = new TreeNode(sContentType.Name);

                                                string configValue = Convert.ToString(sList.ID) + ";" + sContentType.Id;
                                                //if (sListConfigValue != null)
                                                //{
                                                if (sListConfigValue.Contains(configValue))
                                                {
                                                    cTypeNode.Checked = true;
                                                }
                                                //}
                                                listNode.ChildNodes.Add(cTypeNode);
                                                isChildList = true;
                                                break;
                                            }
                                        }
                                    }
                                }
                                //rootNode.ChildNodes.Add(listNode);
                                if (isChildList)
                                {
                                    ContentTypeTvw.Nodes.Add(listNode);
                                }
                            }
                            ContentTypeTvw.ShowCheckBoxes = TreeNodeTypes.Leaf;
                            ContentTypeTvw.ExpandDepth = 1;

                        }
                    }
                });
            }
            return initialStatus;
        }

        private ArrayList getConfigItem(SPWeb _web, string mListID, string mContentTypeID)
        {
            ArrayList sListInfo = new ArrayList();
            if (!string.IsNullOrEmpty(mListID) && !string.IsNullOrEmpty(mContentTypeID))
            {
                try
                {
                    SPList configList = _web.Lists[Constants.LookupForm_Config_NAME];
                    SPQuery query = new SPQuery();
                    query.Query = "<Where><And><Eq><FieldRef Name='Title' /><Value Type='Text'>" + mListID + "</Value></Eq><Eq><FieldRef Name='mContentType' /><Value Type='Text'>" + mContentTypeID + "</Value></Eq></And></Where>";
                    SPListItemCollection items = configList.GetItems(query);
                    if (items.Count > 0)
                    {
                        string sListValue = Convert.ToString(items[0]["sTitle"]);
                        string sContentTypeValue = Convert.ToString(items[0]["sContentType"]);

                        if (!string.IsNullOrEmpty(sListValue) && !string.IsNullOrEmpty(sContentTypeValue))
                        {
                            if (sListValue.Contains(";"))
                            {
                                string[] sLists = sListValue.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                                string[] sCTs = sContentTypeValue.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                                for (int i = 0; i < sLists.Length; i++)
                                {
                                    sListInfo.Add(sLists[i] + ";" + sCTs[i]);
                                }
                            }
                            else
                            {
                                sListInfo.Add(sListValue + ";" + sContentTypeValue);
                            }
                        }
                    }
                }
                catch { }
            }
            return sListInfo;
        }

        private bool updateConfigList(SPWeb _web, string mListID, string mContentTypeID)
        {
            bool updated = false;
            string sListValue = "";
            string sContentTypeValue = "";
            Dictionary<string, string> subListInfo = new Dictionary<string, string>();
            foreach (TreeNode checkedNode in ContentTypeTvw.CheckedNodes)
            {
                try
                {
                    SPList sList = _web.Lists[checkedNode.Parent.Value];
                    SPContentType sCT = sList.ContentTypes[checkedNode.Value];
                    sListValue += Convert.ToString(sList.ID) + ";";
                    sContentTypeValue += Convert.ToString(sCT.Id) + ";";
                }
                catch { }
            }

            if (!string.IsNullOrEmpty(sListValue) && !string.IsNullOrEmpty(sContentTypeValue))
            {
                try
                {
                    SPList configList = _web.Lists[Constants.LookupForm_Config_NAME];
                    SPQuery query = new SPQuery();
                    query.Query = "<Where><And><Eq><FieldRef Name='Title' /><Value Type='Text'>" + mListID + "</Value></Eq><Eq><FieldRef Name='mContentType' /><Value Type='Text'>" + mContentTypeID + "</Value></Eq></And></Where>";
                    SPListItemCollection items = configList.GetItems(query);
                    if (items.Count > 0)
                    {
                        SPListItem item = configList.Items[0];
                        string sTitleValue_old = Convert.ToString(item["sTitle"]);
                        string sContentType_old = Convert.ToString(item["sContentType"]);
                        if (!(sTitleValue_old.Equals(sListValue) && sContentType_old.Equals(sContentTypeValue)))
                        {
                            item["sTitle"] = sListValue;
                            item["sContentType"] = sContentTypeValue;
                            item.Update();
                        }
                        updated = true;
                    }
                    else
                    {
                        SPListItem item = configList.Items.Add();
                        item["Title"] = mListID;
                        item["mContentType"] = mContentTypeID;
                        item["sTitle"] = sListValue;
                        item["sContentType"] = sContentTypeValue;
                        item.Update();
                        updated = true;
                    }
                }
                catch { }
            }
            return updated;
        }
        
        #endregion

        #region GenerateXSN

        private void InitialContextVar(string _siteUrl, Guid _webId, Guid _mlistId)
        {
            if (context == null)
            {
                context = new InfoPathContext();
            }
            mSite = new SPSite(_siteUrl);
            // 101
            context.CurrentSiteUrl = _siteUrl;
            context.XsnName = "template";
            mWeb = mSite.OpenWeb(_webId);
            context.Web = mWeb;
            mList = mWeb.Lists[_mlistId];
            context.ListName = mList.Title;
            context.ListID = mList.ID.ToString();
            context.PageUrl = Context.Request.Url;
            context.MainListFullUrl = context.CurrentSiteUrl + mList.RootFolder.ServerRelativeUrl;
            context.SecondListInfos = new List<ListInfo>();
        }

        private bool isCustomizeFormExist(string _siteUrl, SPWeb web, SPList list, SPContentType CT)
        {
            string destFolderUrl = web.Url + "/" + CT.ResourceFolder.Url;
            string xsnLocation = destFolderUrl + "/template.xsn";
            if (web.GetFile(xsnLocation).Exists)
            {
                return true;
            }
            else return false;
        }

        private void GenerateXSN()
        {
            ListInfo keyListInfo = null;
            context.AddListNames(mList.Title);
            context.SelectedContent.Add(mList.Title, contentTypeName);
            keyListInfo = CreateListInfo(mList.Title, contentTypeName);

            context.XsnName = "template";

            foreach (TreeNode checkedNode in ContentTypeTvw.CheckedNodes)
            {
                ListInfo subListInfo = CreateSubListInfo(checkedNode.Parent.Value, checkedNode.Value);
                context.SecondListInfos.Add(subListInfo);
                keyListInfo.LookupLists.Add(subListInfo);
            }

            StartCreateInfoPath(keyListInfo);
            UploadFileToFormLib();
        }

        private void UploadFileToFormLib()
        {
            try
            {
                System.Threading.Thread.Sleep(1000);
                // SPUtility.CreateFolderUnderList(mWeb,mList.Title,"defaultInfoPath");
                string xsnNam = context.XsnName + ".xsn";
                string m_xsn_location = SPUtility.CreateFile(Site, Web, mList, cTypeResrouceFolder, xsnNam, GetXsnFileStream());

                context.XsnLocation = m_xsn_location;
                //SPList list = Web.Lists[NameSpaceConstants.Name_FormLib];
                //SPUtility.CreateFileUnderDocLib(Web, list, xsnNam, GetXsnFileStream());
            }
            catch (Exception ex)
            {
                LTException.Text = ex.ToString();
                errorPanel.Visible = true;
                //File.WriteAllText(@"c:\a1.txt", ex.ToString());
            }
            //SPUtility.ClearAllItemsInFolder(mList, mList.RootFolder.SubFolders["defaultInfoPath"]);
            //Dictionary<string, string> dic = new Dictionary<string, string>();
            //dic.Add("Title", context.XsnName);
            //SPListItem item = SPUtility.CreateItemUnderFolder(mList, mList.RootFolder.SubFolders["defaultInfoPath"], dic);
            //SPUtility.AddFileToListItem(mList,item, context.XsnName + "_infoPath" + ".xsn", GetXsnFileStream());
            //string desPath = mWeb.Url + "/" + mList.Title + "/defaultInfoPath/" + context.XsnName + "_infoPath" + ".xsn";
            //SPUtility.UploadFileToDocumentLibrary(context.XsnPath, desPath);
        }

        private byte[] GetXsnFileStream()
        {
            byte[] buf = new byte[100];
            List<byte> bytes = new List<byte>();
            using (FileStream fs = File.Open(context.XsnPath, FileMode.Open, FileAccess.Read))
            {
                int offset = 0;
                int len = 0;
                while ((len = fs.Read(buf, offset, buf.Length)) > 0)
                {
                    CopyOneStreamToStream(buf, bytes);
                    buf = new byte[100];
                }
            }

            return bytes.ToArray();
        }

        private void CopyOneStreamToStream(byte[] byte1, List<byte> byte2)
        {
            foreach (byte bt in byte1)
            {
                byte2.Add(bt);
            }
        }

        private void StartCreateInfoPath(ListInfo listInfo)
        {
            //先初始化模板文件的根目录和目标文件的根目录
            string templateFilePath = Server.MapPath("/_layouts/InfoBus2010/template/");
            string destPath = Server.MapPath("/_layouts/InfoBus2010/TempXsnFiles/");
            NameSpaceConstants.TemplateRootPath = templateFilePath;
            if (!Directory.Exists(NameSpaceConstants.Des_Root_Path))
            {
                Directory.CreateDirectory(NameSpaceConstants.Des_Root_Path);
            }

            context.MainListFields = listInfo.Fields;
            CreateFieldLogic cl = new CreateFieldLogic(listInfo, context);
            cl.BeginToCreate();
        }

        private ListInfo CreateListInfo()
        {
            List<string> litNames = new List<string>();
            litNames.Add(mList.Title);
            ListInfo keyListInfo = null;

            context.AddListNames(mList.Title);
            string ctrid = CreateRadbtnID(mList.Title);
            string ctName = contentTypeName;

            context.SelectedContent.Add(mList.Title, ctName);
            keyListInfo = CreateListInfo(mList.Title, ctName);

            return keyListInfo;
        }

        private string CreateRadbtnID(string listTitle)
        {
            return string.Format("ctl00$PlaceHolderMain$sec{0}${0}##", listTitle);
        }

        private ListInfo CreateListInfo(string listTitle, string ctNam)
        {
            ListInfo listInfo = new ListInfo();
            listInfo.Name = listTitle;
            listInfo.Fields = new List<FieldInfo>();

            SPContentType ct = this.mWeb.Lists[listTitle].ContentTypes[ctNam];
            cTypeResrouceFolder = ct.ResourceFolder.Name;
            foreach (SPField fld in ct.Fields)
            {
                //TO DO..
                if (fld.StaticName == "ContentType")
                {
                    continue;
                }

                if (fld.ReadOnlyField || fld.Hidden)
                {
                    continue;
                }

                FieldInfo fldInfo = new FieldInfo();
                if (fld.Type.Equals(SPFieldType.Calculated))
                {
                    fldInfo.Hidden = true;
                }
                fldInfo.Required = fld.Required;
                FieldInfo mFieldInfo = fldInfo.CreateFieldInfo(fld, mList, ct);
                listInfo.Fields.Add(mFieldInfo);
            }

            // id field is a special, so we need to add it specific.
            SPField field = mList.Fields["ID"];
            FieldInfo idInfo = new FieldInfo();
            listInfo.Fields.Add(idInfo.CreateFieldInfo(field, mList, ct));
            return listInfo;
        }

        private ListInfo CreateSubListInfo(string listTitle, string ctName)
        {
            ListInfo listInfo = new ListInfo();
            listInfo.Name = listTitle;
            listInfo.CTypeName = ctName;
            listInfo.Fields = new List<FieldInfo>();
            listInfo.ListId = this.mWeb.Lists[listTitle].ID.ToString();

            SPContentType ct = this.mWeb.Lists[listTitle].ContentTypes[ctName];
            listInfo.CTypeId = ct.Id.ToString();
            foreach (SPField fld in ct.Fields)
            {
                //TO DO..
                if (fld.StaticName == "ContentType")
                {
                    continue;
                }

                if (fld.ReadOnlyField || fld.Hidden)
                {
                    continue;
                }

                if (fld.Type.Equals(SPFieldType.Lookup))
                {
                    continue;
                }

                FieldInfo fldInfo = new FieldInfo();
                if (fld.Type.Equals(SPFieldType.Calculated))
                {
                    fldInfo.Hidden = true;
                }
                fldInfo.Required = fld.Required;
                listInfo.Fields.Add(fldInfo.CreateFieldInfo(fld, mList, ct));
            }

            // id field is a special, so we need to add it specific.
            SPField field = mList.Fields["ID"];
            FieldInfo idInfo = new FieldInfo();
            listInfo.Fields.Add(idInfo.CreateFieldInfo(field, mList, ct));
            return listInfo;
        }
        #endregion

        #region RegisterEventReceiver

        private static void RegisterEventReceiver(SPList _list)
        {
            SPEventReceiverDefinition def1 = _list.EventReceivers.Add();
            def1.Assembly = "ServBus.ListForm2010, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=df5827f77359eb0a";
            def1.Class = "ServBus.ListForm2010.SPFieldChangeEvent.SPFieldChangeEvent";
            def1.Type = SPEventReceiverType.FieldAdded;
            def1.Name = "SPFieldChangeEventFieldAdded";
            def1.Synchronization = SPEventReceiverSynchronization.Synchronous;
            def1.SequenceNumber = 1000;
            def1.Update();

            SPEventReceiverDefinition def2 = _list.EventReceivers.Add();
            def2.Assembly = "ServBus.ListForm2010, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=df5827f77359eb0a";
            def2.Class = "ServBus.ListForm2010.SPFieldChangeEvent.SPFieldChangeEvent";
            def2.Type = SPEventReceiverType.FieldUpdated;
            def2.Name = "SPFieldChangeEventFieldUpdated";
            def2.Synchronization = SPEventReceiverSynchronization.Synchronous;
            def2.SequenceNumber = 1000;
            def2.Update();

            SPEventReceiverDefinition def3 = _list.EventReceivers.Add();
            def3.Assembly = "ServBus.ListForm2010, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=df5827f77359eb0a";
            def3.Class = "ServBus.ListForm2010.SPFieldChangeEvent.SPFieldChangeEvent";
            def3.Type = SPEventReceiverType.FieldDeleting;
            def3.Name = "SPFieldChangeEventFieldDeleting";
            def3.Synchronization = SPEventReceiverSynchronization.Synchronous;
            def3.SequenceNumber = 1000;
            def3.Update();
        }

        private static void UnBindingEventReceiver(SPList _list)
        {
            List<string> eventReceiverList = new List<string>();
            eventReceiverList.Add("SPFieldChangeEventFieldAdded");
            eventReceiverList.Add("SPFieldChangeEventFieldUpdated");
            eventReceiverList.Add("SPFieldChangeEventFieldDeleting");
            for (int i = 0; i < _list.EventReceivers.Count; i++)
            {
                SPEventReceiverDefinition def = _list.EventReceivers[i];
                if (eventReceiverList.Contains(def.Name))
                {
                    def.Delete();
                    i--;
                }
            }
        }

        #endregion
    }
}
